<?php
/**
 * 日志类
 *
 * @version $Id$
 * @package if
 * @subpackage util.log
 */
class ILog extends IObject {
	private $logs = array();
	
	/**
	 * 普通信息
	 *
	 */
	const LOG_INFO = 1;
	
	/**
	 * 调试信息
	 *
	 */
	const LOG_DEBUG = 2;
	
	/**
	 * 警告信息
	 *
	 */
	const LOG_WARNING = 4;
	
	/**
	 * 致命错误信息
	 *
	 */
	const LOG_FATAL = 8;
	
	/**
	 * 过滤器
	 *
	 * @var ILogFilter
	 */
	private $filter;
	
	/**
	 * writer列表
	 *
	 * @var array
	 */
	private $writerList = array();
	
	/**
	 * 日志默认的前缀
	 *
	 */
	const DEFAULT_LOG_PREFIX = "%{a} - %{t} - %{U} - %{m}";
	
	/**
	 * 级别
	 *
	 * @var integer
	 * @since 1.0
	 */
	private $level;
	
	private static $instance;
	
	private function __construct() {
		
	}
	
	/**
	 * Enter description here...
	 *
	 * @return ILog
	 */
	static function singleton() {
		if (!self::$instance) {
			self::$instance = new self;
		}
		return self::$instance;
	}
	
	/**
	 * 设置级别
	 *
	 * @param integer $level LOG_XXX
	 * @since 1.0
	 */
	function setLevel($level) {
		$this->level = $level;
	}
	
	/**
	 * 取得级别
	 *
	 * @return integer
	 * @since 1.0
	 */
	function level() {
		if (!$this->level) {
			$this->level = o("@log.level");
		}
		return $this->level;
	}
	
	/**
	 * 打印info(普通信息)信息
	 *
	 * @param string $msg 日志信息
	 * @param string $prefix 前缀
	 */
	function info($msg, $prefix = null) {
		if ($this->level() <= self::LOG_INFO) {
			$this->output("info", $msg, $prefix);
		}
	}
	
	/**
	 * 打印fatal(致命错误)信息
	 * 
	 * 将会抛出异常，并导致程序终止运行
	 *
	 * @param string $msg 日志信息
	 */	
	function fatal($msg) {
		if ($this->level() <= self::LOG_FATAL) {
			throw new IException("fatal error: " . $msg, 0x100036);
		}
	}
	
	/**
	 * 打印warning(警告)信息
	 *
	 * @param string $msg 日志信息
	 * @param string $prefix 前缀
	 */	
	function warning($msg, $prefix = null) {
		if ($this->level() <= self::LOG_WARNING) {
			$this->output("warning", $msg, $prefix);
		}
	}
	
	/**
	 * 打印debug(调试)信息
	 *
	 * @param string $msg 日志信息
	 * @param string $prefix 前缀
	 */	
	function debug($msg, $prefix = null) {
		if ($this->level() <= self::LOG_DEBUG) {
			$this->output("debug", $msg, $prefix);
		}
	}
	
	/**
	 * 输出信息
	 *
	 * @param string $type 日志类型
	 * @param string $msg 日志信息
	 * @param string $prefix 前缀
	 */
	private function output($type, $msg, $prefix) {
		if (!isset($this->logs[$type])) {
			$this->logs[$type] = array();
		}
		
		//prefix
		if (!$prefix) {
			$prefix = self::DEFAULT_LOG_PREFIX;
		}
		$message = $prefix . " - " . $type . ": " . $msg . "\n";
		
		//提取配置
		$stdout = o("@log.stdout");
		$file = o("@log.file");
		if (empty($this->writerList) &&  (is_null($stdout) || $stdout)) {//no writer list
			if (!$this->filter) {
				$this->setFilter(IRegistry::singleton()->single("ISimpleLogFilter"));
			}
			$this->filter->doFilter($message);
			array_push($this->logs[$type], $msg);
		}
		if ($file != "" && empty($this->writerList)) {
			$this->addWriter(new IFileLogWriter($file), $this->filter);
		}
		if (!empty($this->writerList)) {//have writer list
			foreach ($this->writerList as $config) {
				$writer = $config["writer"];
				$filter = $config["filter"];
				$filter->doFilter($message);
				$writer->write($message);
			}
		}
	}
	
	/**
	 * 取得所有的日志
	 *
	 * @return array
	 */
	function logs() {
		return $this->logs;
	}
	
	/**
	 * 设定日志的过滤器
	 * 
	 * 处理日志中的特殊字符（比如%{a}, %{U}等等）
	 *
	 * @param ILogFilter $filter 过滤器
	 */
	function setFilter(ILogFilter $filter) {
		$this->filter = $filter;
	}
	
	/**
	 * 添加writer
	 * 
	 * 建议只有在调试期添加日志记录器，以免影响效率和系统性能
	 * 
	 * @param ILogWriter $writer writer
	 * @param ILogFilter $filter 过滤器
	 */
	function addWriter(ILogWriter $writer, $filter = null) {
		if (!$filter) {
			$filter = IRegistry::singleton()->single("ISimpleLogFilter");
		}
		$this->writerList[] = array("writer"=>$writer, "filter"=>$filter);
	}
	
	/**
	 * 取得writer列表
	 *
	 * @return array
	 */
	function writers() {
		return $this->writerList;
	}
	
	/**
	 * 关闭writer列表
	 *
	 */
	function closeWriters() {
		foreach ($this->writerList as $config) {
			$writer = $config["writer"];
			$writer->close();
		}
	}
	
	/**
	 * 加入日志
	 *
	 * @param string $msg 日志消息
	 * @param integer $level 级别
	 * @since 1.0
	 */
	function log($msg, $level = self::LOG_DEBUG) {
		if ($level == self::LOG_DEBUG) {
			$this->debug($msg);
		}
		else if ($level == self::LOG_FATAL) {
			$this->fatal($msg);
		}
		else if ($level == self::LOG_INFO) {
			$this->info($msg);
		}
		else if ($level == self::LOG_WARNING) {
			$this->warning($msg);
		}
	}
	
	/**
	 * 输出到标准设备
	 *
	 * @since 1.0
	 */
	function stdout() {
		$types = array("info", "debug", "warning", "fatal");
		foreach ($types as $type) {
			if (!empty($this->logs[$type])) {
				echo "<table border=\"0\" cellspacing=\"1\" bgcolor=\"#eeeeee\" style=\"font:12px 'Courier New'\" width=\"100%\">
						<tr>
							<td><strong style=\"font-size:14px;\">{$type}</strong></td>
						</tr>
						<tr>
							<td><ul>";
				foreach ($this->logs[$type] as $msg) {
					echo "<li>" . $msg . "</li>";
				}
				echo "</ul></td>
						</tr>
					</table>";
			}
		}
	}
}

?>